<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vue 3 数据渲染流程可视化</title>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
        font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
      }
      body {
        background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);
        color: #333;
        min-height: 100vh;
        padding: 20px;
      }
      .container {
        max-width: 1200px;
        margin: 0 auto;
        background: rgba(255, 255, 255, 0.9);
        border-radius: 15px;
        box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
        overflow: hidden;
      }
      header {
        background: #4caf50;
        color: white;
        padding: 20px;
        text-align: center;
      }
      h1 {
        font-size: 2.5rem;
        margin-bottom: 10px;
      }
      .subtitle {
        font-size: 1.2rem;
        opacity: 0.9;
      }
      .content {
        display: flex;
        padding: 20px;
        gap: 20px;
      }
      .visualization {
        flex: 1;
        background: white;
        border-radius: 10px;
        padding: 20px;
        box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
      }
      .explanation {
        flex: 1;
        background: #f9f9f9;
        border-radius: 10px;
        padding: 20px;
        box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
      }
      h2 {
        color: #2c3e50;
        margin-bottom: 15px;
        padding-bottom: 10px;
        border-bottom: 2px solid #eee;
      }
      .steps {
        display: flex;
        flex-direction: column;
        gap: 15px;
        margin-top: 20px;
      }
      .step {
        padding: 15px;
        border-radius: 8px;
        background: white;
        box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
        transition: all 0.3s ease;
      }
      .step.active {
        transform: translateX(10px);
        border-left: 5px solid #4caf50;
      }
      .step-number {
        display: inline-block;
        width: 30px;
        height: 30px;
        background: #4caf50;
        color: white;
        border-radius: 50%;
        text-align: center;
        line-height: 30px;
        margin-right: 10px;
      }
      .flow-container {
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 20px;
        margin-top: 20px;
      }
      .flow-step {
        width: 100%;
        padding: 15px;
        border-radius: 8px;
        background: #e8f5e9;
        text-align: center;
        position: relative;
        transition: all 0.5s ease;
      }
      .flow-step.active {
        background: #4caf50;
        color: white;
        transform: scale(1.05);
      }
      .arrow {
        font-size: 24px;
        color: #4caf50;
        transition: all 0.5s ease;
      }
      .arrow.active {
        color: #ff9800;
        transform: scale(1.2);
      }
      .demo-area {
        margin-top: 30px;
        padding: 20px;
        background: #f5f5f5;
        border-radius: 8px;
        text-align: center;
      }
      button {
        background: #4caf50;
        color: white;
        border: none;
        padding: 12px 24px;
        border-radius: 5px;
        cursor: pointer;
        font-size: 16px;
        margin-top: 15px;
        transition: background 0.3s;
      }
      button:hover {
        background: #388e3c;
      }
      .counter {
        font-size: 2rem;
        font-weight: bold;
        color: #2c3e50;
        margin: 15px 0;
      }
      .code-snippet {
        background: #2d2d2d;
        color: #f8f8f2;
        padding: 15px;
        border-radius: 5px;
        margin: 15px 0;
        font-family: "Courier New", monospace;
        overflow-x: auto;
      }
      .highlight {
        color: #ff9800;
        font-weight: bold;
      }
    </style>
  </head>
  <body>
    <div id="app" class="container">
      <header>
        <h1>Vue 3 数据到渲染流程可视化</h1>
        <div class="subtitle">理解Vue响应式原理与渲染机制</div>
      </header>

      <div class="content">
        <div class="visualization">
          <h2>可视化流程</h2>
          <div class="flow-container">
            <div class="flow-step" :class="{ active: currentStep >= 1 }">
              <span class="step-number">1</span>
              响应式数据初始化 (ref/reactive)
            </div>

            <div class="arrow" :class="{ active: currentStep >= 2 }">↓</div>

            <div class="flow-step" :class="{ active: currentStep >= 2 }">
              <span class="step-number">2</span>
              依赖收集 (Effect/ReactiveEffect)
            </div>

            <div class="arrow" :class="{ active: currentStep >= 3 }">↓</div>

            <div class="flow-step" :class="{ active: currentStep >= 3 }">
              <span class="step-number">3</span>
              数据变更触发依赖
            </div>

            <div class="arrow" :class="{ active: currentStep >= 4 }">↓</div>

            <div class="flow-step" :class="{ active: currentStep >= 4 }">
              <span class="step-number">4</span>
              组件重新渲染
            </div>

            <div class="arrow" :class="{ active: currentStep >= 5 }">↓</div>

            <div class="flow-step" :class="{ active: currentStep >= 5 }">
              <span class="step-number">5</span>
              虚拟DOM生成与对比
            </div>

            <div class="arrow" :class="{ active: currentStep >= 6 }">↓</div>

            <div class="flow-step" :class="{ active: currentStep >= 6 }">
              <span class="step-number">6</span>
              真实DOM更新 (Patch)
            </div>
          </div>

          <div class="demo-area">
            <h3>演示: 计数器</h3>
            <div class="counter">{{ count }}</div>
            <button @click="increment">增加计数</button>
            <button @click="reset">重置</button>
          </div>
        </div>

        <div class="explanation">
          <h2>流程解释</h2>

          <div class="steps">
            <div class="step" :class="{ active: currentStep === 1 }">
              <span class="step-number">1</span>
              <strong>响应式数据初始化</strong>
              <p>
                使用 <span class="highlight">ref</span> 或
                <span class="highlight">reactive</span> 创建响应式数据。
              </p>
              <div class="code-snippet">const count = ref(0);</div>
            </div>

            <div class="step" :class="{ active: currentStep === 2 }">
              <span class="step-number">2</span>
              <strong>依赖收集</strong>
              <p>Vue在组件渲染时追踪响应式数据的依赖关系。</p>
              <div class="code-snippet">
                // Vue自动追踪依赖 effect(() => { // 这个effect依赖于count.value
                console.log(count.value); });
              </div>
            </div>

            <div class="step" :class="{ active: currentStep === 3 }">
              <span class="step-number">3</span>
              <strong>数据变更触发依赖</strong>
              <p>当数据发生变化时，Vue通知所有依赖进行更新。</p>
              <div class="code-snippet">count.value++; // 触发更新</div>
            </div>

            <div class="step" :class="{ active: currentStep === 4 }">
              <span class="step-number">4</span>
              <strong>组件重新渲染</strong>
              <p>Vue调度组件重新渲染，生成新的虚拟DOM树。</p>
              <div class="code-snippet">
                // 重新执行渲染函数 const vnode = render();
              </div>
            </div>

            <div class="step" :class="{ active: currentStep === 5 }">
              <span class="step-number">5</span>
              <strong>虚拟DOM对比 (Diff算法)</strong>
              <p>Vue比较新旧虚拟DOM树，找出需要更新的部分。</p>
              <div class="code-snippet">
                // 对比新旧VNode patch(oldVNode, newVNode);
              </div>
            </div>

            <div class="step" :class="{ active: currentStep === 6 }">
              <span class="step-number">6</span>
              <strong>真实DOM更新</strong>
              <p>Vue将变化应用到实际DOM上，完成视图更新。</p>
              <div class="code-snippet">
                // 应用变更到真实DOM el.textContent = newValue;
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>

    <script>
      const { createApp, ref, onMounted } = Vue;

      createApp({
        setup() {
          const count = ref(0);
          const currentStep = ref(0);

          const increment = () => {
            // 重置步骤演示
            currentStep.value = 0;

            // 模拟流程步骤
            setTimeout(() => (currentStep.value = 1), 200);
            setTimeout(() => (currentStep.value = 2), 400);
            setTimeout(() => (currentStep.value = 3), 600);

            // 更新数据
            count.value++;

            setTimeout(() => (currentStep.value = 4), 800);
            setTimeout(() => (currentStep.value = 5), 1000);
            setTimeout(() => (currentStep.value = 6), 1200);
          };

          const reset = () => {
            count.value = 0;
            currentStep.value = 0;
          };

          onMounted(() => {
            // 初始演示
            setTimeout(() => {
              currentStep.value = 1;
              setTimeout(() => (currentStep.value = 2), 300);
              setTimeout(() => (currentStep.value = 3), 600);
              setTimeout(() => (currentStep.value = 4), 900);
              setTimeout(() => (currentStep.value = 5), 1200);
              setTimeout(() => (currentStep.value = 6), 1500);
            }, 1000);
          });

          

          return {
            count,
            currentStep,
            increment,
            reset,
          };
        },
      }).mount("#app");
    </script>
  </body>
</html>
